#include "MyTcpServer.h"

#include <QMetaType>

namespace
{
#define ADDRESS "0.0.0.0"
#define PORT 5555

}

#pragma comment(lib,"../Lib/HPSocket/x64/HPSocket_D.lib")

void MyTcpServer::on_pushButton_stop_clicked()
{
    if (m_server)
    {
        if (m_server->Stop())
        {
            LogMsg("close server success");
            SetWidgetState(WidgetState::STOPED_STATE);
        }
        else
        {
            LogMsg("close server fail");
        }
    }
}

void MyTcpServer::on_pushButton_disconn_clicked()
{
    QString _id{ ui.lineEdit_id->text() };
    if (m_server)
    {
        if (_id.isEmpty())
        {
            LogMsg("Please input id");
            return;
        }
        bool _flag{false};
        int _nid{};
        if (_nid = _id.toInt(&_flag), !_flag)
        {
            LogMsg(QString("id is invalid data"));
            return;
        }

        if (m_server->Disconnect(_nid))
        {
            LogMsg(QString("id:[%1] disconnect success").arg(_nid));
        }else
            LogMsg(QString("id:[%1] disconnect fail").arg(_nid));
    }
}

void MyTcpServer::SetWidgetState(WidgetState state)
{
    m_widget_state = state;
    ui.pushButton_start->setEnabled(WidgetState::STOPED_STATE == m_widget_state);
    ui.pushButton_stop->setEnabled(WidgetState::STARTED_STATE == m_widget_state);
    ui.pushButton_disconn->setEnabled(WidgetState::STARTED_STATE == m_widget_state);
    ui.lineEdit_addr->setEnabled(WidgetState::STOPED_STATE == m_widget_state);
    ui.lineEdit_id->setEnabled(WidgetState::STARTED_STATE == m_widget_state);
}

void MyTcpServer::LogMsg(const QString& info)
{
    QPlainTextEdit* ptr{ ui.plainTextEdit };
    if (ptr)
    {
        if (500 <= ptr->document()->blockCount())
            ptr->clear();
        ptr->appendPlainText(info);
    }
}

void MyTcpServer::on_pushButton_start_clicked()
{
    SetWidgetState(WidgetState::STARTING_STATE);
    if (m_server)
    {
        if (m_server->Start((LPCTSTR)ADDRESS, PORT))
        {
            LogMsg(QString("addr:[%1],port:[%2] start success").arg(ADDRESS).arg(PORT));
            SetWidgetState(WidgetState::STARTED_STATE);
        }
        else
        {
            LogMsg(QString("addr:[%1],port:[%2] start fail").arg(ADDRESS).arg(PORT));
            SetWidgetState(WidgetState::STOPED_STATE);
        }
    }
}

MyTcpServer::MyTcpServer(QWidget *parent)
    : QMainWindow(parent)
    , m_server{this}
{
    ui.setupUi(this);

    OnInitDialog();
    InitSlot();
}

void MyTcpServer::OnInitDialog()
{
    qRegisterMetaType<WidgetState>("WidgetState");
    qRegisterMetaType<WidgetState>("WidgetState&");
    SetWidgetState(WidgetState::STOPED_STATE);
}

void MyTcpServer::InitSlot()
{
    connect(this, &MyTcpServer::signal_log_msg, this, &MyTcpServer::LogMsg);
    connect(this, &MyTcpServer::signal_widget_state, this, &MyTcpServer::SetWidgetState);
}

EnHandleResult MyTcpServer::OnPrepareListen(ITcpServer* pSender, SOCKET soListen)
{
    char buf[64]{};
    int _len = sizeof(buf) / sizeof(char);
    unsigned short _port{};
    if (pSender)
    {
        if (pSender->GetListenAddress((TCHAR*)buf, _len, _port))
            LogMsg(QString("bind ip:[%1],port:[%2] success").arg(QString::fromLatin1(buf)).arg(_port));
        else
            LogMsg(QString("bind ip:[%1],port:[%2] fail").arg(QString::fromLatin1(buf)).arg(_port));
    }
    return HR_OK;
}

EnHandleResult MyTcpServer::OnAccept(ITcpServer* pSender, CONNID dwConnID, UINT_PTR soClient)
{
    char buf[64]{};
    int _len = sizeof(buf) / sizeof(char);
    unsigned short _port{};
    QString _reject_ip{ ui.lineEdit_addr->text() };
    BOOL _ret{ TRUE };
    if (pSender)
    {
        pSender->GetRemoteAddress(dwConnID,(TCHAR*)buf, _len, _port);
        if (0 == _reject_ip.compare(QString::fromLatin1(buf)))
            _ret = FALSE;
            
    }
    return _ret ? HR_OK : HR_ERROR;
}

EnHandleResult MyTcpServer::OnHandShake(ITcpServer* pSender, CONNID dwConnID)
{
    return HR_OK;
}

EnHandleResult MyTcpServer::OnReceive(ITcpServer* pSender, CONNID dwConnID, int iLength)
{
    ITcpPullServer* pServer = ITcpPullServer::FromS(pSender);
    
    {
        char* buf = (char*)alloca(iLength);
        EnFetchResult _result = pServer->Fetch(dwConnID,(BYTE*)buf, iLength);
        if (FR_OK == _result)
        {
            TestStruct _info{};
            memcpy_s(&_info, sizeof(_info), buf, iLength);
            QString _str = QString::fromLatin1(_info.buf);
            emit signal_log_msg(QString("receive id:[%1],data:[%2],length:[%3]").arg(dwConnID).arg(_str).arg(iLength));
            if (!pServer->Send(dwConnID, (BYTE*)_info.buf, iLength))
                return HR_ERROR;
        }
    }
    return HR_OK;
}

EnHandleResult MyTcpServer::OnSend(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
{
    emit signal_log_msg(QString("send id:[%1],data:[%2],length:[%3]").arg(dwConnID).arg(QString::fromLatin1((char *)pData)).arg(iLength));
    return HR_OK;
}

EnHandleResult MyTcpServer::OnShutdown(ITcpServer* pSender)
{
    return HR_OK;
}

EnHandleResult MyTcpServer::OnClose(ITcpServer* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)
{
    if (SE_OK == iErrorCode)
        emit signal_log_msg(QString("id:[%1] close success").arg(dwConnID));
    else
        emit signal_log_msg(QString("id:[%1] close fail").arg(dwConnID));
    return HR_OK;
}
